package core;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;

/**
 * Parses a simple tagged text with tagged data in the format:
 * 
 *   [element /attributes/]
 *   /text/
 * 
 * Typically only the element has to exist for the tag to be considered valid
 * (although, blank tags are still returned).
 * 
 * @author john
 *
 */
public class WTagFormat {
	
	/**
	 * Parses a stream of characters into an array of WTagBlocks,
	 * which consist of three String fields: element, attribute, and text.
	 * @param r
	 * @return
	 */
	public static WTagBlock[] parse(InputStreamReader r) {
		try {
			BufferedReader br = new BufferedReader(r);
			StringBuilder sb = new StringBuilder();
			int i;
			while((i = br.read()) != -1)
				sb.append((char)i);
			
			return parse(sb.toString());
		} 
		catch (IOException ex) {
			ex.printStackTrace();
			return null;
		}
	}
	
	public static WTagBlock[] parse(String str) {
		ArrayList<WTagBlock> blocks = new ArrayList<WTagBlock>();
		WTagBlock current = new WTagBlock("");
		
		boolean inText = true,		// start reading a block even without a block header
				inTag = false;
		StringBuilder tag = new StringBuilder();
		StringBuilder text = new StringBuilder(160);	// set initial capacity to an arbitrary 160 chars
		char c;
		
		for (int i=0; i<str.length(); i++) {
			switch (c = str.charAt(i)) {
			case '[':
				// if an open bracket is encountered within a tag
				if (inTag) {
					inText = false;
					System.err.println("Misformed tag encountered: " + tag.toString());
					tag = new StringBuilder();		// clear bad tag
					if (current != null)			// if there was text read before the bad tag
						text = new StringBuilder(current.getText());	// add it to the previous block
				}
				
				// if we were previously reading a block of text,
				//  stop and store it
				else if (inText && text.length() > 0) {
					current.setText(text.toString());
					if (blocks.size() == 0 || blocks.get(blocks.size() - 1) != current)
						blocks.add(current);
					text = new StringBuilder();
					inText = false;
				}
				// start reading a tag
				inTag = true;
				break;
			
			case ']':
				if (inTag) {
					inTag = false;
					inText = true;
					
					current = new WTagBlock(tag.toString());
					tag = new StringBuilder();
					
					//System.out.println("tag read: " + tag.toString());
				}
				else {
					System.err.println("Closing brace without opening encountered");
				}
				break;
				
			case '\r':
			case '\n':
				if(inTag) {
					inTag = false;
					System.err.println("Misformed tag encountered: " + tag.toString());
					tag = new StringBuilder();
					inText = true;
				}
				else if (inText)
					text.append(c);
				break;
			
			default:
				if(inTag)
					tag.append(c);
				else if(inText)
					text.append(c);
				break;
			}
		}
		
		current.setText(text.toString());
		blocks.add(current);
		
		return blocks.toArray(new WTagBlock[blocks.size()]);
	}
}